home *** CD-ROM | disk | FTP | other *** search
- /*
- * projector.c
- *
- * Copyright (C) 1989, 1991, Craig E. Kolb
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- * Projector light source itself written and copyrighted by Greg Spencer and
- * given to the Public Domain, with the above conditions.
- *
- * projector.c,v 4.1 1994/08/09 07:57:14 explorer Exp
- *
- * projector.c,v
- * Revision 4.1 1994/08/09 07:57:14 explorer
- * Bump version to 4.1
- *
- * Revision 1.1.1.1 1994/08/08 04:52:04 explorer
- * Initial import. This is a prerelease of 4.0.6enh3, or 4.1 possibly.
- *
- */
- #include "light.h"
- #include "projector.h"
- #ifdef __SASC
- #define M_PI PI
- #endif
-
- static LightMethods *iProjectorMethods = NULL;
-
- Projectorlight *
- ProjectorCreate(from, to, up, image, uangle, vangle, falloff)
- Vector *from, *to, *up;
- ImageText *image;
- Float uangle,vangle;
- int falloff;
- {
- Projectorlight *projector; /* pointer for projector object */
-
- /* allocate space for projector */
- projector = (Projectorlight *)share_malloc(sizeof(Projectorlight));
-
- projector->pos = *from;
- VecSub(*to, *from, &projector->dir);
- if (VecNormalize(&projector->dir) == 0.) {
- RLerror(RL_ABORT,"Invalid projectorlight specification.\n");
- return (Projectorlight *)NULL;
- }
-
- /*
- * If angles are zero, set it to 0.5 degrees -- just to keep from
- * exploding...
- */
- if ((uangle==0.0)||(vangle==0.0)) uangle=vangle=0.5;
-
- /* note: these are solid angles, not spherical coords */
- projector->uangle = ((uangle*M_PI)/180.0);
- projector->vangle = ((vangle*M_PI)/180.0);
- projector->v = *up;
-
- /* find a u direction for the projector from v and direction */
- VecNormCross(up,&projector->dir,&projector->u);
-
- /* if falloff is true, then use r^2 falloff, otherwise ignore it */
- projector->falloff=falloff;
-
- projector->image = image;
- return projector;
- }
-
- LightMethods *
- ProjectorMethods()
- {
- if (iProjectorMethods == (LightMethods *)NULL) {
- iProjectorMethods = LightMethodsCreate();
- iProjectorMethods->intens = ProjectorIntens;
- iProjectorMethods->dir = ProjectorDirection;
- }
- return iProjectorMethods;
- }
-
- /*
- * Calculate intensity ('color') of light reaching 'pos' from light 'lp'.
- * The projectorlight is 'dist' units from 'pos' along 'dir'.
- *
- * Returns TRUE if non-zero illumination, FALSE otherwise.
- */
- int
- ProjectorIntens(projector, lcolor, cache, ray, dist, noshadow, color)
- Projectorlight *projector;
- ShadowCache *cache;
- Ray *ray;
- Color *lcolor, *color;
- int noshadow;
- Float dist;
- {
- Color imagecolor;
- extern Float ProjectorAtten();
- Float dist2;
-
- color->r = lcolor->r;
- color->g = lcolor->g;
- color->b = lcolor->b;
-
- /*
- * Compute projectorlight color -- return if outside image
- */
- if (ProjectorImageApply(projector, ray, &imagecolor)
- == FALSE) return FALSE;
- /*
- * If outside of projector, return FALSE.
- */
- if (imagecolor.r+imagecolor.g+imagecolor.b == 0.)
- return FALSE;
- if (Shadowed(color, lcolor, cache, ray, dist, noshadow))
- return FALSE;
-
- if (projector->falloff) {
- dist2= dist*dist;
- if (dist2 < 1.0) dist2=1.0; /* below 1.0, falloff is closer to 1:1 */
- color->r *= imagecolor.r/dist2;
- color->g *= imagecolor.g/dist2;
- color->b *= imagecolor.b/dist2;
- }
- else {
- color->r *= imagecolor.r;
- color->g *= imagecolor.g;
- color->b *= imagecolor.b;
- }
- return TRUE;
- }
-
- /*
- * Map Image to the 'dir' direction
- * adapted from ImageTextApply.
- */
- int
- ProjectorImageApply(pl, ray, imagecolor)
- Projectorlight *pl;
- Ray *ray;
- Color *imagecolor;
- {
- Float fx, fy; /* sub-pixel coords */
- ImageText *text; /* imagetext input */
- Float outval[4], outval_u[4], outval_v[4]; /* returned color values */
- Float u, v; /* whole-valued u-v coords */
- Float rdotu, rdotv, rdotp; /* dot products */
- int ix, iy; /* integer u-v components */
- int rchan, gchan, bchan; /* position of channels in input */
- Vector rdir; /* ray direction */
-
- text=pl->image;
- rdir.x= -ray->dir.x;
- rdir.y= -ray->dir.y;
- rdir.z= -ray->dir.z;
- rdotp = dotp(&rdir, &pl->dir);
- /*
- * Check to see if ray is behind projectorlight.
- * also eliminates the possibility of a divide by zero
- * later on (if we come in exactly at 90 degrees from
- * light direction)
- */
- if (rdotp <= 0.000001) return FALSE;
-
- /*
- * pos is position of origin of the ray
- * pl->pos is the position of the projector
- * pl->dir is the direction the projector points in
- * dir is the direction from the ray origin to the projector
- */
-
- rdotu= dotp(&rdir,&pl->u);
- rdotv= dotp(&rdir,&pl->v);
-
- u= text->tileu/2.0+atan(rdotu/rdotp)/pl->uangle;
- v= text->tilev/2.0+atan(rdotv/rdotp)/pl->vangle;
-
- /*
- * Handle tiling at this point.
- * (merely checks to see if we're outside the tile space)
- */
-
- if (TileValue(text->tileu, text->tilev, u, v)) return FALSE;
-
- u -= floor(u); /* remove all but fractional portion */
- v -= floor(v);
- fx = u * (Float) text->image->width; /* multiply by size */
- fy = v * (Float) text->image->height;
- ix = fx; /* round to integer */
- iy = fy;
- fx = fx - (Float) ix; /* find out sub-pixel address */
- fy = fy - (Float) iy;
-
- /* handle alpha */
- if (text->image->has_alpha) {
- /* Alpha channel is 0 */
- rchan = 1;
- gchan = 2;
- bchan = 3;
- } else {
- rchan = 0;
- gchan = 1;
- bchan = 2;
- }
-
- /* handle grey-scale */
- if (text->image->chan == 1) {
- gchan = rchan;
- bchan = rchan;
- }
-
- /* interpolate a sub-pixel value from the image */
- ImageIndex(text->image, ix, iy, fx, fy, text->smooth, outval);
-
- /*
- * escape when alpha is zero, 'cause there is no change
- */
- if (text->image->has_alpha && (outval[0] < 0.001))
- return FALSE;
-
- imagecolor->r=outval[rchan];
- imagecolor->g=outval[gchan];
- imagecolor->b=outval[bchan];
- return TRUE;
- }
-
- void
- ProjectorDirection(lp, pos, dir, dist)
- Projectorlight *lp;
- Vector *pos, *dir;
- Float *dist;
- {
- /*
- * Calculate dir from position to center of light source.
- */
- VecSub(lp->pos, *pos, dir);
- *dist = VecNormalize(dir);
- }
-
- ProjectorMethodRegister(meth)
- UserMethodType meth;
- {
- if (iProjectorMethods)
- iProjectorMethods->user = meth;
- }
-